package com.nstar.base.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.nstar.base.dao.BaseDAO;


public class BaseDAOImpl extends HibernateDaoSupport implements BaseDAO {

    public BaseDAOImpl() {
        super();
    }


//    /**
//     *
//     * @param sql a query expressed in SQL
//     * @param returnAlias a table alias that appears inside {} in the SQL string
//     * @param returnClass the returned persistent class
//     * @return a Query object
//     */
//    public Query createSQLQuery(String sql, String returnAlias, Class returnClass) {
//        Query queryObject = getSession().createSQLQuery(sql, returnAlias, returnClass);
//        SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
//        return queryObject;
//    }
//
//    /**
//     *
//     * @param sql a query expressed in SQL
//     * @param returnAlias an array of table aliases that appear inside {} in the SQL string
//     * @param returnClass the returned persistent classes
//     * @return a Query object
//     */
//    public Query createSQLQuery(String sql, String[] returnAlias, Class[] returnClass) {
//        Query queryObject = getSession().createSQLQuery(sql, returnAlias, returnClass);
//        SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
//        return queryObject;
//    }



    // SELECT

    /**
     *
     * @param entityClass a persistent class
     * @return a List containing 0 or more persistent instances
     */
    public List loadAll(Class entityClass) {
        return getHibernateTemplate().loadAll(entityClass);
    }

    /**
     *
     * @param entityClass a persistent class
     * @param id an identifier of the persistent instance
     * @return the persistent instance, or null if not found
     */
    public Object get(Class entityClass, Serializable id) {
        return getHibernateTemplate().get(entityClass, id);
    }

    /**
     *
     * @param queryString a query expressed in Hibernate's query language
     * @return a List containing 0 or more persistent instances
     */
    public List find(String queryString) {
        return getHibernateTemplate().find(queryString);
    }

    /**
     *
     * @param queryString a query expressed in Hibernate's query language
     * @param values the value of the parameter
     * @return a List containing 0 or more persistent instances
     */
    public List find(String queryString, Object value) {
        return getHibernateTemplate().find(queryString, value);
    }

    /**
     *
     * @param queryString a query expressed in Hibernate's query language
     * @param values the values of the parameters
     * @return a List containing 0 or more persistent instances
     */
    public List find(String queryString, Object[] values) {
        return getHibernateTemplate().find(queryString, values);
    }

    /**
     *
     * @param queryString a query expressed in Hibernate's query language
     * @param values the values of the parameters
     * @param types Hibernate types of the parameters
     * @return a List containing 0 or more persistent instances
     */
//    public List find(String queryString, Object[] values, Type[] types) {
//        return getHibernateTemplate().find(queryString, values, types);
//    }



    // INSERT

    /**
     *
     * @param entity the transient instance to persist
     * @return the identifier to assign
     */
    public Serializable save(Object entity) {
        return getHibernateTemplate().save(entity);
    }



    // UPDATE

    /**
     *
     * @param entity the persistent instance to update
     * @return 1 if update the instance succeeded; 0 if the corresponding
     * database entry doesn't exist already
     */
    public int update(Object entity) {
        try {
//            getHibernateTemplate().update(entity, LockMode.UPGRADE_NOWAIT);
            getHibernateTemplate().update(entity);
            return 1;
        }
        catch (OptimisticLockingFailureException e) {
            return 0;
        }
    }

    public int saveOrUpdate(Object entity) {
        try {
            getHibernateTemplate().saveOrUpdate(entity);
            return 1;
        }
        catch (OptimisticLockingFailureException e) {
            return 0;
        }
    }



    // DELETE

    /**
     *
     * @param entity the persistent instance to delete
     * @return 1 if delete the instance completed; 0 if the corresponding
     * database entry doesn't exist already
     */
    public int delete(Object entity) {
        try {
//            getHibernateTemplate().delete(entity, LockMode.UPGRADE_NOWAIT);
            getHibernateTemplate().delete(entity);
            return 1;
        }
        catch (OptimisticLockingFailureException e) {
            return 0;
        }
    }

    public int delete(Class entityClass, Serializable id) {
        try {
            Object obj = get(entityClass, id);
            if (obj == null) return 0;
//            getHibernateTemplate().delete(obj, LockMode.UPGRADE_NOWAIT);
            getHibernateTemplate().delete(obj);
            return 1;
        }
        catch (OptimisticLockingFailureException e) {
            return 0;
        }
    }

    /**
     *
     * @param queryString a query expressed in Hibernate's query language
     * @return the number of instances deleted
     */
    public int delete(final String queryString) {
        Integer deleteCount = (Integer)  getHibernateTemplate().execute(
                new HibernateCallback() {
                    public Object doInHibernate(Session session) throws HibernateException {
                        checkWriteOperationAllowed(session);
                        session.delete(queryString);
                        //return null;
                    }
        });
        return deleteCount.intValue();
    }
    



    /**
     * Check whether write operations are allowed on the given Session.
     * <p>Default implementation throws an InvalidDataAccessApiUsageException
     * in case of FlushMode.NEVER. Can be overridden in subclasses.
     *
     * @param session current Hibernate Session
     * @throws InvalidDataAccessApiUsageException if write operations are not allowed
     * @see net.sf.hibernate.Session#getFlushMode
     * @see net.sf.hibernate.FlushMode#NEVER
     */
    protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
        if (FlushMode.NEVER.equals(session.getFlushMode())) {
            throw new InvalidDataAccessApiUsageException(
                    "Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session " +
                    "into FlushMode.AUTO respectively remove 'readOnly' marker from transaction definition");
        }
    }
}
